在前面的章節,只有介紹 DX 如何設定 Shader pipeline 跟部份的 Shader 程式,在這篇會更詳細介紹 HLSL 本身的寫法與相關功能。
在硬體的歷史中,CPU 是先出現的,其中組合語言、C、C++ 被創造出來的目的就是用來控制 CPU 相關的計算操作。
在這之後,為了應付日漸複雜的圖學計算,GPU 被創造出來的同時也開始有對應的語言來負責 GPU 的操作。HLSL 就是用來控制 GPU 的語言。
HLSL 宣告變數基本上跟 C++ 相似,為型別 變數名稱;
//Ex:
float3 pos;
pos = float3(1, 1, 1);
常見的如下
| 型別 | 說明 |
|---|---|
| bool | 布林值,表示 true 或 false |
| int | 整數,可以表示正整數、負整數與 0 |
| uint | 整數,只能表示 0 或正整數。主要用在索引 ID 這類資料 |
| float | 單精度浮點數,表示帶有小數的值 |
| float2 | 由 2 個 float 組成的向量,例如 (x, y),常用於 UV、2D 座標 |
| float3 | 由 3 個 float 組成的向量,例如 (x, y, z),常用於位置、方向、法線 |
| float4 | 由 4 個 float 組成的向量,例如 (x, y, z, w),常用於齊次座標或 RGBA 顏色 |
| float3x3 | 由 3 × 3 個 float 組成的矩陣,常用於旋轉、法線等 3D 向量的轉換 |
| float4x4 | 由 4 × 4 個 float 組成的矩陣,常用於 World、View、Projection 等 3D 座標轉換 |
HLSL 除了定義變數的型別,後面還有像這樣的內容
struct VSInput
{
float3 position : POSITION;
float2 uv : TEXCOORD0;
};
struct VSOutput
{
float4 position : SV_POSITION;
};
Semantic 是用來告訴 Shader Compiler 這個資料要如何使用,常見的如下
| 名字 | 說明 |
|---|---|
| POSITION | 物件空間的頂點座標 |
| COLOR | 頂點顏色 |
| TEXCOORD | 基本用法為 UV 座標 |
其中 TEXCOORD 特別說基本用法為 UV 的原因,其實是因為他不限於 UV 座標,他可以是當成是一種泛用 Shader Compiler 可以理解的資料格式,像是以下的例子 Compiler 都可以理解的
struct VS_OUT
{
float4 position : SV_POSITION;
float2 uv : TEXCOORD0;
float3 normal : TEXCOORD1;
float3 worldPos : TEXCOORD2;
float3 color : TEXCOORD3;
};
而前綴 SV_ 是告訴資料最後要輸出出去
//Vertex Shader 要出最後的頂點位置供 Rasterizer 使用
struct VSOutput
{
float4 position : SV_POSITION;
};
接下來的範例會常看到類似這樣的設定
cbuffer CameraData : register(b0)
{
float4x4 viewProjection;
};
RWStructuredBuffer<float4> outputBuffer : register(u0);
這設定是因為 CPU 與 GPU 使用不同的記憶體位址空間,需要讓 C++ 在 CPU 設定的值有辦法傳遞到 GPU,而 Graphics API 會把 GPU 資源綁定在 Shader 能辨識的 Slot (位址)裡,而 register() 就是在指定這個資源要使用哪個 Slot。
而對應的資源前綴如下
| b | Constant Buffer |
|---|---|
| t | Texture |
| c | Buffer offset |
| s | Sampler |
| u | Unordered Access View |
saturate()將數值限制在 0 ~ 1 的範圍
saturate(-1.0f); // 0
saturate(0.5f); // 0.5
saturate(2.0f); // 1
clamp()將數值限制在指定的最小值與最大值之間
clamp(-1.0f, 0.0f, 1.0f); // 0
clamp(0.5f, 0.0f, 1.0f); // 0.5
clamp(2.0f, 0.0f, 1.0f); // 1
min()比較兩個值,回傳較小的值
min(3.0f, 5.0f); // 3
min(8.0f, 2.0f); // 2
max()比較兩個值,回傳較大的值
max(3.0f, 5.0f); // 5
max(8.0f, 2.0f); // 8
abs()取得數值的絕對值
abs(-5.0f); // 5
abs(5.0f); // 5
abs(0.0f); // 0
floor()將數值向下取整
floor(1.2f); // 1
floor(1.9f); // 1
floor(-1.2f); // -2
ceil()將數值向上取整
ceil(1.2f); // 2
ceil(1.9f); // 2
ceil(-1.2f); // -1
round()將數值四捨五入到最接近的整數
round(1.2f); // 1
round(1.6f); // 2
round(2.5f); // 2
frac()只取得數值的小數部分
frac(1.25f); // 0.25
frac(3.75f); // 0.75
frac(5.0f); // 0
sqrt()計算平方根
sqrt(4.0f); // 2
sqrt(9.0f); // 3
sqrt(25.0f); // 5
pow()計算次方。
pow(2.0f, 2.0f); // 4
pow(2.0f, 3.0f); // 8
pow(3.0f, 2.0f); // 9
sin()計算正弦值。
sin(0.0f); // 0
cos()計算餘弦值。
cos(0.0f); // 1
sin() 與 cos() 常用在旋轉、波浪、週期運動這類的視覺表現
length()計算 Vector 的長度。
float3 value = float3(3, 4, 0);
float len = length(value); // 5
distance()計算兩個點之間的距離。
float3 a = float3(0, 0, 0);
float3 b = float3(3, 4, 0);
float d = distance(a, b); // 5
normalize()將向量標準化,使它的長度變成 1。用於拿到向量方向後方便計算。
float3 direction = float3(10, 0, 0);
float3 result = normalize(direction);
// (1, 0, 0)
dot()計算兩個 Vector 的內積
float3 a = float3(1, 0, 0);
float3 b = float3(1, 0, 0);
float result = dot(a, b); // 1
如果兩個 Vector 都已經標準化的,就可以從此數值得知兩向量彼此方向的對應關係
dot = 1 → 完全同方向
dot = 0 → 約 90 度
dot = -1 → 完全反方向
cross()計算兩個 Vector 的外積,結果會得到一個同時垂直於兩者的新 Vector
float3 xAxis = float3(1, 0, 0);
float3 yAxis = float3(0, 1, 0);
float3 result = cross(xAxis, yAxis); // (0, 0, 1)
圖為這樣
yAxis
(0, 1, 0)
↑
│
│
●──────── → xAxis
/ (1, 0, 0)
/
↗
result = (0, 0, 1)
Z Axis
lerp()在兩個數值之間進行線性插值。
lerp(0.0f, 10.0f, 0.0f); // 0
lerp(0.0f, 10.0f, 0.5f); // 5
lerp(0.0f, 10.0f, 1.0f); // 10
step()根據指定的臨界值,回傳 0 或 1
//step(edge, x); x < edge → 0 x >= edge → 1
step(0.5f, 0.2f); // 0
step(0.5f, 0.5f); // 1
step(0.5f, 0.8f); // 1
smoothstep()和 step() 類似,但會在兩個範圍之間平滑地從 0 過渡到 1
//smoothstep(min, max, value);
smoothstep(0.0f, 1.0f, 0.0f); // 0
smoothstep(0.0f, 1.0f, 0.5f); // 約 0.5
smoothstep(0.0f, 1.0f, 1.0f); // 1
mul()進行 Vector 與 Matrix,或 Matrix 與 Matrix 的乘法
float4 worldPosition =
mul(
float4(position, 1.0f),
worldMatrix
);
在 HLSL 中常用於座標轉換
Local Space
↓ World Matrix
World Space
↓ View Matrix
View Space
↓ Projection Matrix
Clip Space
當然實際上 HLSL 還有更多功能,剩下的會在接下來的章節中介紹出來
HLSL シェーダーの魔導書 シェーディングの基礎からレイトレーシングまで